﻿// Inner Fire 游戏引擎库
// DxMeshFactory - Mesh工场
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于生成与保存最简单的Mesh。比如线段，Quad。
// 使用Singlton模式。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-23

#include "dx_mesh_factory.h"
#include <EASTL/array.h>

using namespace DirectX;

using F3 = DirectX::XMFLOAT3;
using F2 = DirectX::XMFLOAT2;

namespace ifire::dx {

DxMeshFactory* DxMeshFactory::instance = nullptr;

static eastl::vector<Vertex> create_quad_vertices(
    float width = 1.0f, float height = 1.0f) {
  // 计算半宽高（使面片中心在原点）
  const float hw = width * 0.5f;
  const float hh = height * 0.5f;

  eastl::vector<Vertex> vertices = {
      {F3(-hw, -hh, 0.0f), F3(0, 0, 1), F2(0, 1), F3(1, 0, 0)}, // 顶点0：左下角
      {F3(hw, -hh, 0.0f), F3(0, 0, 1), F2(1, 1), F3(1, 0, 0)}, // 顶点1：右下角
      {F3(-hw, hh, 0.0f), F3(0, 0, 1), F2(0, 0), F3(1, 0, 0)}, // 顶点2：左上角
      {F3(hw, hh, 0.0f), F3(0, 0, 1), F2(1, 0), F3(1, 0, 0)} // 顶点3：右上角
  };

  return vertices;
}

// 生成立方体顶点数据
static eastl::vector<Vertex> create_cube_vertex(float size) {
  // 立方体半边长
  const float hs = size * 0.5f;

  // 定义立方体6个面的顶点数据（每个面4个顶点）
  eastl::vector<Vertex> vertices = {// 前面 (Z正方向)
      {F3(-hs, -hs, hs), F3(0, 0, 1), F2(0, 1), F3(1, 0, 0)},
      {F3(hs, -hs, hs), F3(0, 0, 1), F2(1, 1), F3(1, 0, 0)},
      {F3(hs, hs, hs), F3(0, 0, 1), F2(1, 0), F3(1, 0, 0)},
      {F3(-hs, hs, hs), F3(0, 0, 1), F2(0, 0), F3(1, 0, 0)},

      // 后面 (Z负方向)
      {F3(hs, -hs, -hs), F3(0, 0, -1), F2(0, 1), F3(-1, 0, 0)},
      {F3(-hs, -hs, -hs), F3(0, 0, -1), F2(1, 1), F3(-1, 0, 0)},
      {F3(-hs, hs, -hs), F3(0, 0, -1), F2(1, 0), F3(-1, 0, 0)},
      {F3(hs, hs, -hs), F3(0, 0, -1), F2(0, 0), F3(-1, 0, 0)},

      // 左面 (X负方向)
      {F3(-hs, -hs, -hs), F3(-1, 0, 0), F2(0, 1), F3(0, 0, 1)},
      {F3(-hs, -hs, hs), F3(-1, 0, 0), F2(1, 1), F3(0, 0, 1)},
      {F3(-hs, hs, hs), F3(-1, 0, 0), F2(1, 0), F3(0, 0, 1)},
      {F3(-hs, hs, -hs), F3(-1, 0, 0), F2(0, 0), F3(0, 0, 1)},

      // 右面 (X正方向)
      {F3(hs, -hs, hs), F3(1, 0, 0), F2(0, 1), F3(0, 0, -1)},
      {F3(hs, -hs, -hs), F3(1, 0, 0), F2(1, 1), F3(0, 0, -1)},
      {F3(hs, hs, -hs), F3(1, 0, 0), F2(1, 0), F3(0, 0, -1)},
      {F3(hs, hs, hs), F3(1, 0, 0), F2(0, 0), F3(0, 0, -1)},

      // 下面 (Y负方向)
      {F3(-hs, -hs, -hs), F3(0, -1, 0), F2(0, 1), F3(1, 0, 0)},
      {F3(hs, -hs, -hs), F3(0, -1, 0), F2(1, 1), F3(1, 0, 0)},
      {F3(hs, -hs, hs), F3(0, -1, 0), F2(1, 0), F3(1, 0, 0)},
      {F3(-hs, -hs, hs), F3(0, -1, 0), F2(0, 0), F3(1, 0, 0)},

      // 上面 (Y正方向)
      {F3(-hs, hs, hs), F3(0, 1, 0), F2(0, 1), F3(1, 0, 0)},
      {F3(hs, hs, hs), F3(0, 1, 0), F2(1, 1), F3(1, 0, 0)},
      {F3(hs, hs, -hs), F3(0, 1, 0), F2(1, 0), F3(1, 0, 0)},
      {F3(-hs, hs, -hs), F3(0, 1, 0), F2(0, 0), F3(1, 0, 0)}};

  return vertices;
}

// 生成立方体索引数据（使用三角形列表）
static eastl::vector<uint16_t> create_cube_indices() {
  return {// 前面
      0, 1, 2, 0, 2, 3,
      // 后面
      4, 5, 6, 4, 6, 7,
      // 左面
      8, 9, 10, 8, 10, 11,
      // 右面
      12, 13, 14, 12, 14, 15,
      // 下面
      16, 17, 18, 16, 18, 19,
      // 上面
      20, 21, 22, 20, 22, 23};
}

void DxMeshFactory::CreateSystemMesh(
    ID3D12Device* device, ID3D12GraphicsCommandList* cmd) {
  // 保存，不用每次都传递
  device_ = device;
  cmd_ = cmd;

  // CUBE
  auto vertices = create_cube_vertex(1.0f);
  auto indices = create_cube_indices();
  mesh_cube_ = CreateMesh("CUBE", vertices, indices);

  // UIQUAD，也用于空对象
  eastl::vector<UIVertex> ui_vertices = {
      {{F2(-1.0f, -1.0f), F2(0.0f, 0.0f)}, {F2(1.0f, -1.0f), F2(1.0f, 0.0f)},
          {F2(1.0f, 1.0f), F2(1.0f, 1.0f)}, {F2(-1.0f, 1.0f), F2(0.0f, 1.0f)}}};
  indices = {0, 1, 2, 0, 2, 3};
  ui_quad_ = CreateMesh("UIQUAD", ui_vertices, indices);

  // QUAD和双面QUAD
  vertices = create_quad_vertices();
  indices = {0, 1, 2, 1, 3, 2};
  mesh_quad_ = CreateMesh("QUAD", vertices, indices);
  indices = {0, 1, 2, 1, 3, 2, 2, 1, 0, 2, 3, 1};
  mesh_dual_quad_ = CreateMesh("DUALQUAD", vertices, indices);

  // 线段
  vertices = {//
      {F3(0, 0, 0), F3(0, 1, 0), F2(0, 0.5f), F3(1, 0, 0)},
      {F3(1, 0, 0), F3(0, 1, 0), F2(1, 0.5f), F3(1, 0, 0)}};
  indices = {0, 1};
  mesh_line_ = CreateMesh("LINE", vertices, indices);
}

template <typename T>
DxMesh* DxMeshFactory::CreateMesh(ikit::sstr name,
    const eastl::vector<T>& vertices, const eastl::vector<uint16_t>& indices) {
  auto mesh = std::make_unique<DxMesh>(0, name);
  dx::DxMeshCreateDesc desc{};
  desc.pVertexData = (void*)vertices.data();
  desc.pIndexData = (void*)indices.data();
  desc.VertexSize = vertices.size();
  desc.VertexStrideSize = sizeof(T);
  desc.IndexSize = indices.size();
  desc.IndexFormat = DXGI_FORMAT_R16_UINT;
  desc.IndexStrideSize = sizeof(std::uint16_t);
  mesh->CreateResource(device_, cmd_, desc);
  mesh->AddSubmesh("Default", 0, 0, static_cast<UINT>(desc.IndexSize), 0, 0);

  // 加入到项目中
  auto ptr = mesh.get();
  meshes_.push_back(std::move(mesh));
  map_[name.uid()] = ptr;
  return ptr;
}

DxMesh* DxMeshFactory::GetMesh(ikit::sstr name) const {
  auto it = map_.find(name.uid());
  return it != map_.end() ? it->second : nullptr;
}

} // namespace ifire::dx